#include "app_dp_notify.h"

extern app_time_rec_t sg_time_rec[];
extern app_time_rec_mgr_t sg_time_rec_mgr;
#define INT_TO_ARRAY(x, v)     \
    (x)[0] = (v >> 24) & 0xFF; \
    (x)[1] = (v >> 16) & 0xFF; \
    (x)[2] = (v >> 8) & 0xFF;  \
    (x)[3] = value & 0xFF
#define SHORT_TO_ARRAY(x, v)  \
    (x)[0] = (v >> 8) & 0xFF; \
    (x)[2] = value & 0xFF

static void app_dp_signal_pkt_value_to_send(unsigned char dpid, unsigned char type, unsigned int value)
{
    unsigned char tx[64] = {0x00};
    unsigned char offset = 0x00;

    tx[offset++] = dpid;
    tx[offset++] = type;
    tx[offset++] = 0x00;

    if (type == DP_TYPE_BOOL || type == DP_TYPE_ENUM)
    {
        tx[offset++] = 0x01;
        tx[offset++] = value & 0xFF;
    }
    else if (type == DP_TYPE_NUMBER)
    {
        tx[offset++] = 0x04;
        tx[offset++] = (value >> 24) & 0xFF;
        tx[offset++] = (value >> 16) & 0xFF;
        tx[offset++] = (value >> 8) & 0xFF;
        tx[offset++] = value & 0xFF;
    }
    else if (type == DP_TYPE_BITMAP)
    {
        if (value > 0xFFFF)
        {
            tx[offset++] = 0x04;
            INT_TO_ARRAY(&tx[offset], value);
            offset += 4;
        }
        else if (value > 0xFF)
        {
            tx[offset++] = 0x02;
            SHORT_TO_ARRAY(&tx[offset], value);
            offset += 2;
        }
        else
        {
            tx[offset++] = 0x01;
            tx[offset++] = value & 0xFF;
        }
    }

    app_uart_tx_dp_notify(tx, offset);
}

static void app_dp_signal_pkt_data_to_send(unsigned char dpid, unsigned char type, unsigned char *data, unsigned short length)
{
    ret_if_true(type != DP_TYPE_RAW && type != DP_TYPE_STRING)

    unsigned char tx[128] = {0x00};
    unsigned char offset = 0x00;

    tx[offset++] = dpid;
    tx[offset++] = type;
    tx[offset++] = (length >> 8) & 0xFF;
    tx[offset++] = length & 0xFF;

    if (length > 0x00)
    {
        memcpy((void *)&tx[offset], data, length);
    }
    offset += length;

    app_uart_tx_dp_notify(tx, offset);
}

static unsigned char app_dp_multi_pkt_value(unsigned char *buff, unsigned char dpid, unsigned char type, unsigned int value)
{
    unsigned char *ptr = buff;
    *ptr++ = dpid;
    *ptr++ = type;
    *ptr++ = 0x00;

    if ((type == DP_TYPE_ENUM) || (type == DP_TYPE_BOOL))
    {
        *ptr++ = 0x01;
        *ptr++ = value & 0xFF;
    }
    else if (type == DP_TYPE_NUMBER)
    {
        *ptr++ = 0x04;
        *ptr++ = (value >> 24) & 0xFF;
        *ptr++ = (value >> 16) & 0xFF;
        *ptr++ = (value >> 8) & 0xFF;
        *ptr++ = value & 0xFF;
    }
    else if (type == DP_TYPE_BITMAP)
    {
        if (value > 0xFFFF)
        {
            *ptr++ = 0x04;
            INT_TO_ARRAY(ptr, value);
            ptr += 4;
        }
        else if (value > 0xFF)
        {
            *ptr++ = 0x02;
            SHORT_TO_ARRAY(ptr, value);
            ptr += 2;
        }
        else
        {
            *ptr++ = 0x01;
            *ptr++ = value & 0xFF;
        }
    }

    return (ptr - buff);
}

static unsigned char app_dp_multi_pkt_data(unsigned char *buff, unsigned char dpid, unsigned char type, unsigned char *data, unsigned short length)
{
    ret_val_if_true(type != DP_TYPE_STRING && type != DP_TYPE_RAW, 0x00)

        unsigned char *ptr = buff;
    *ptr++ = dpid;
    *ptr++ = type;
    *ptr++ = (length >> 8) & 0xFF;
    *ptr++ = length & 0xFF;

    if (length > 0x00)
    {
        memcpy(ptr, data, length);
    }
    ptr += length;

    return (ptr - buff);
}

void app_dp_meal_plan_notify(void)
{
    unsigned char buffer[USER_FLASH_DATA_SIZE] = {0x00};

    unsigned char offset = app_plan_get(buffer, USER_FLASH_DATA_SIZE);
    app_dp_signal_pkt_data_to_send(DP_MEAL_PLAN, DP_TYPE_RAW, buffer, offset);
}

void app_dp_manual_feed_notify(void)
{
    app_dp_signal_pkt_value_to_send(DP_MANUAL_FEED, DP_TYPE_NUMBER, dp_obj->value);
}

void app_dp_feed_state_notify(void)
{
    app_dp_signal_pkt_value_to_send(DP_FEED_STATE, DP_TYPE_ENUM, dp_obj->state);
}

void app_dp_fault_notify(void)
{
    app_dp_signal_pkt_value_to_send(DP_FAULT, DP_TYPE_BITMAP, dp_obj->fault);
}

void app_dp_feed_report_notify(void)
{
    app_dp_signal_pkt_value_to_send(DP_FEED_REPORT, DP_TYPE_NUMBER, dp_obj->result);
}

void app_dp_bat_notify(void)
{
    app_dp_signal_pkt_value_to_send(DP_BAT, DP_TYPE_NUMBER, dp_obj->bat);
}

void app_dp_all_notify(void)
{
    unsigned char tx[256] = {0x00};
    unsigned short offset = 0x00;
    //offset += app_dp_multi_pkt_value(&tx[offset], DP_MANUAL_FEED, DP_TYPE_NUMBER, dp_obj->value);
    offset += app_dp_multi_pkt_value(&tx[offset], DP_FEED_STATE, DP_TYPE_ENUM, dp_obj->state);
    offset += app_dp_multi_pkt_value(&tx[offset], DP_FAULT, DP_TYPE_BITMAP, dp_obj->fault);
    offset += app_dp_multi_pkt_value(&tx[offset], DP_FEED_REPORT, DP_TYPE_NUMBER, dp_obj->result);
    offset += app_dp_multi_pkt_value(&tx[offset], DP_BAT, DP_TYPE_NUMBER, dp_obj->bat);

    unsigned char buffer[USER_FLASH_DATA_SIZE] = {0x00};
    unsigned char length = app_plan_get(buffer, USER_FLASH_DATA_SIZE);
    if (length > 0)
    {
        offset += app_dp_multi_pkt_data(&tx[offset], DP_MEAL_PLAN, DP_TYPE_RAW, buffer, length);
    }

    app_uart_tx_dp_notify(tx, offset);
}

void app_dp_notify_task(void)
{
    unsigned char data[6] = {0};

    if (dp_notify->all)
    {
        app_dp_all_notify();
        dp_notify->all = 0x00;
    }
    else
    {
        if (dev_obj->tuya_net == TUYA_NET_OK)
        {
            if (sg_time_rec_mgr.sum_count >= 1)
            {
                unsigned char page_seek = 0;      // 页定位
                unsigned char page_remainder = 0; // 当前页的喂食数据偏移

                page_seek = sg_time_rec_mgr.sum_count / 21;
                page_remainder = sg_time_rec_mgr.sum_count % 21;

                data[0] = sg_time_rec[page_seek].DATA[page_remainder - 1].year;
                data[1] = sg_time_rec[page_seek].DATA[page_remainder - 1].month;
                data[2] = sg_time_rec[page_seek].DATA[page_remainder - 1].day;
                data[3] = sg_time_rec[page_seek].DATA[page_remainder - 1].hour;
                data[4] = sg_time_rec[page_seek].DATA[page_remainder - 1].mins;
                data[5] = sg_time_rec[page_seek].DATA[page_remainder - 1].result;

                app_uart_tx_dp_notify_record(data, 6);
                sg_time_rec_mgr.sum_count -= 1;
                if (sg_time_rec_mgr.sum_count == 0)
                {
                    app_clear_time_rec();
                }
            }
        }
    }
}
